package com.apes.fn.scm.retailOrder.service.account.retail;

import com.alibaba.fastjson.JSONObject;
import com.apes.fn.mdm.serveTypeContrast.ServeTypeContrast;
import com.apes.fn.mdm.serveTypeContrast.ServeTypeContrastRepository;
import com.apes.fn.scm.retailOrder.model.RetailOrder;
import com.apes.fn.scm.retailOrder.model.RetailOrderDiscount;
import com.apes.fn.scm.retailOrder.model.RetailOrderPayMethod;
import com.apes.fn.scm.retailOrder.repository.RetailOrderDiscountRepository;
import com.apes.fn.scm.retailOrder.repository.RetailOrderRepository;
import com.apes.fn.scm.retailOrder.service.NoInventoryRetailItemsService;
import com.apes.fn.scm.retailOrder.service.account.BackBatchAndSupplierService;
import com.apes.fn.scm.retailOrder.service.account.RetailAccountData;
import com.apes.fn.server.servicePlan.model.ServicePlan;
import com.apes.fn.server.servicePlan.model.ServicePlanItem;
import com.apes.fn.server.servicePlan.repository.ServicePlanItemRepository;
import com.apes.framework.api.SpringManager;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.Arith;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.ReflectUtil;
import com.apes.scm.account.account.model.AccountingMethod;
import com.apes.scm.account.account.model.InventoryMode;
import com.apes.scm.account.tax.model.Tax;
import com.apes.scm.account.tax.service.TaxService;
import com.apes.scm.contract.model.Contract;
import com.apes.scm.contract.service.ContractService;
import com.apes.scm.masterdata.finance.model.CrossIC;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.product.model.Product;
import com.apes.scm.masterdata.product.model.ServeType;
import com.apes.scm.voucher.model.Voucher;
import com.apes.scm.voucher.model.VoucherInventory;
import com.apes.scm.voucher.model.VoucherItem;
import com.apes.scm.voucher.repository.VoucherInventoryRepository;
import com.apes.scm.voucher.service.BusinessType;
import com.apes.scm.voucher.service.VoucherType;
import com.google.common.util.concurrent.AtomicDouble;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 异业合作账目
 * 配置到场景流中了，这里加上注解只是为了统一格式
 *
 * @Author wuq
 * @Date 2021-9-23
 */
@RetailAccount(value = "crossIc", name = "异业合作")
@Service
public class CrossICVoucherService extends BackBatchAndSupplierService {

    @Autowired
    private RetailOrderDiscountRepository retailOrderDiscountRepository;
    @Autowired
    private ContractService contractService;
    @Autowired
    private VoucherInventoryRepository voucherInventoryRepository;
    @Autowired
    private NoInventoryRetailItemsService noInventoryRetailItemsService;
    @Autowired
    private ServeTypeContrastRepository serveTypeContrastRepository;
    @Autowired
    private TaxService taxService;

    /**
     * 场景流中执行, 执行入口移入到 RetailOrderFlowInvoiceService#createCrossIC
     * 单位客户上线之后，删除
     *
     * @param request
     */
    @Deprecated
    public void create(SimpleRequest request) {
        String id = request.get("id");
        RetailOrder retailOrder = SpringManager.getBean(RetailOrderRepository.class).findOne(id);
        process(new RetailAccountData(retailOrder));
    }

    public void process(RetailAccountData retailAccountData) {
        RetailOrder retailOrder = retailAccountData.getRetailOrder();

        // 获取兑换券对应服务明细列表
        List<RetailOrderDiscount> retailOrderDiscounts = SpringManager.getBean(RetailOrderDiscountRepository.class).findAllByRetailOrderId(retailOrder.getId());
        List<ServicePlanItem> discountServicePlanItemList = getServicePlanItem(retailOrderDiscounts);
        if (discountServicePlanItemList.size() == 0) return;    // 没有异业合作的方案明细

        // 异业合作零售单销售凭证
        retailCrossIC(retailOrder);

        // 异业合作账目部分
        invoiceCrossIC(retailOrder, discountServicePlanItemList);

        /** 回写零售单折扣表中的票券号码以及数量 **/
        backDiscountData(retailOrderDiscounts, discountServicePlanItemList);
    }

    /**
     * 根据折扣获取对应服务方案明细
     *
     * @param retailOrderDiscounts 零售单折扣明细
     * @return ServicePlanItem
     */
    private List<ServicePlanItem> getServicePlanItem(List<RetailOrderDiscount> retailOrderDiscounts) {
        // 根据异业券找到对应的服务方案明细行
        List<String> servicePlanItemIds = retailOrderDiscounts.stream()
                .filter(RetailOrderDiscount::checkIsCrossIC)  // 找出异业合作的部分
                .map(retailOrderDiscount -> retailOrderDiscount.getRetailOrderItem().getOriginnumber())
                .collect(Collectors.toList());

        return servicePlanItemIds.stream()
                .map(planItemId -> {
                    ServicePlanItem servicePlanItem = SpringManager.getBean(ServicePlanItemRepository.class).findOne(planItemId);
                    if (Objects.isNull(servicePlanItem))
                        throw new RuntimeException("根据传入的编码没有找到对应的明细记录，服务方案明细编码：" + planItemId);
                    return servicePlanItem;
                }).collect(Collectors.toList());
    }

    private void backDiscountData(List<RetailOrderDiscount> retailOrderDiscounts, List<ServicePlanItem> discountServicePlanItemList) {
        retailOrderDiscounts.forEach(retailOrderDiscount -> {
            discountServicePlanItemList.forEach(servicePlanItem -> {
                if (retailOrderDiscount.getRetailOrderItem().getOriginnumber().equals(servicePlanItem.getId())) {
                    retailOrderDiscount.setCouponNumber(servicePlanItem.getExchanceCode());     // 异业兑换码
                    retailOrderDiscount.setCouponUsedQty(servicePlanItem.getQtyExchanceCode()); // 兑换码数量
                }
            });
            retailOrderDiscountRepository.saveAndFlush(retailOrderDiscount);
        });
    }

    private void retailCrossIC(RetailOrder retailOrder) {
        // 采购凭证
        noInventoryRetailItemsService.purchaseVoucher(retailOrder);

        // 销售凭证处理
        createCustomerSaleVoucher(retailOrder);
    }

    private void createCustomerSaleVoucher(RetailOrder retailOrder) {
        Voucher voucher = new Voucher();
        voucher.setBusinessType(BusinessType.SALE_ORDER);
        ReflectUtil.copy(retailOrder, voucher, "dept", "company", "scene","clerk");

        voucher.setPartner(retailOrder.getCompany().getParty().getPatyRoleByType("Customer"));

        voucher.setInventoryMode(InventoryMode.IM_OWN);     //设置库存模式：自有
        voucher.setAccountingMethod(AccountingMethod.AM_PURCHASE);  // 核算方式：经销
        voucher.setCustomerExpand(retailOrder.getCustomerExpand().getId());

        voucher.setOrigin(retailOrder.getId());
        voucher.setOriginBusinessType(retailOrder.getInnerBusinessType());
        voucher.setSource(retailOrder.getId());
        voucher.setSourceBusinessType(retailOrder.getInnerBusinessType());
//        voucher.setClassification(VoucherType.CROSS_IC);

        voucher.setVoucherItems(
                retailOrder.getSaleItems().stream().map(
                        item -> {
                            VoucherItem voucherItem = new VoucherItem();

                            ReflectUtil.copy(item, voucherItem, "product", "uom","supplier", "inventoryBatch");

                            voucherItem.setOwner(item.getOwner());
                            voucherItem.setOriginItemId(item.getId());
                            voucherItem.setSourceItemId(item.getId());

                            voucherItem.setProductQty(item.getProductUomQty());
                            voucherItem.setDiscount(0);

                            Tax tax = taxService.getSaleTax(retailOrder.getCompany(), item.getProduct());
                            voucherItem.setTax(tax);

                            // 找方案上面的价格
                            ServicePlanItem servicePlanItem = SpringManager.getBean(ServicePlanItemRepository.class).findById(item.getOriginnumber()).orElse(null);
                            if (Objects.isNull(servicePlanItem)) throw new RuntimeException("根据销售商品明细没有找到对应的服务方案明细，请检查商品："+ item.getProduct().getId());
                            voucherItem.setPriceUnit(servicePlanItem.getRealPayAmount());      // 获取自费金额
                            voucherItem.setPriceTotal(voucherItem.getPriceUnit());

                            // 检查是否为工单的内协的
                            if (item.getProductRule() == 20) {
                                voucherItem.setSupplier(servicePlanItem.getSupplier());
                                voucherItem.setInventoryBatch(servicePlanItem.getInventoryBatch());
                            }
                            return voucherItem;
                        }).collect(Collectors.toSet())
        );

        // 写入凭证之前验证一次（后期可以删除）
        AtomicDouble payAmount = new AtomicDouble(0);
        retailOrder.getPaymentMethodSet().forEach( retailOrderPayMethod -> {
            // 不计算其他应收
            if (retailOrderPayMethod.checkIsOtherReceivables()) return;
            // 处理APP报错的部分
            if ("12".equals(retailOrderPayMethod.getPaymentMethodType().getId()) && Objects.nonNull(retailOrderPayMethod.getCustomer()) ) return;

            payAmount.set( payAmount.get() + retailOrderPayMethod.getAmount());
        });

        double voucherAmount = voucher.getVoucherItems().stream().mapToDouble(VoucherItem::getPriceTotal).sum();
        if (Math.abs(Arith.round(voucherAmount - payAmount.get(), 2)) > 0.001) {
            throw new RuntimeException("异业合作客户的自费金额与销售凭证金额不相等，请检查！");
        }
        invoke("voucher.create", MapUtil.mapped(voucher));
    }

    private void createCustomerSaleVoucherFix(RetailOrder retailOrder) {
        Voucher voucher = new Voucher();
        voucher.setBusinessType(BusinessType.SALE_ORDER);
        ReflectUtil.copy(retailOrder, voucher, "dept", "company", "scene", "clerk");

        voucher.setPartner(retailOrder.getCompany().getParty().getPatyRoleByType("Customer"));

        voucher.setInventoryMode(InventoryMode.IM_OWN);     //设置库存模式：自有
        voucher.setAccountingMethod(AccountingMethod.AM_PURCHASE);  // 核算方式：经销
        voucher.setCustomerExpand(retailOrder.getCustomerExpand().getId());

        voucher.setOrigin(retailOrder.getId());
        voucher.setOriginBusinessType(retailOrder.getInnerBusinessType());
        voucher.setSource(retailOrder.getId());
        voucher.setSourceBusinessType(retailOrder.getInnerBusinessType());
//        voucher.setClassification(VoucherType.CROSS_IC);

        /** 凭证金额修改 **/
        Set crossPartner = new HashSet<>();
        retailOrder.getSaleItems().forEach(retailOrderItem -> {
            ServicePlanItem servicePlanItem = SpringManager.getBean(ServicePlanItemRepository.class).findById(retailOrderItem.getOriginnumber()).orElse(null);
            if (Objects.isNull(servicePlanItem))
                throw new RuntimeException("根据销售商品明细没有找到对应的服务方案明细，请检查商品：" + retailOrderItem.getProduct().getId());

            crossPartner.add(servicePlanItem.getCrossIC().getPartner().getParty().getPartyRoleByType("Customer").getId());
            crossPartner.add(servicePlanItem.getCrossIC().getCompany().getParty().getPartyRoleByType("Customer").getId());
        });

        double tempAmt = 0.0d;
        for (RetailOrderPayMethod payMethod : retailOrder.getPaymentMethodSet()) {
            // 非其他应收，或者其他应收的收款客户不是异业合作方
            if (!payMethod.checkIsOtherReceivables() || (payMethod.checkIsOtherReceivables() && !crossPartner.contains(payMethod.getCustomer().getId()))) {
                tempAmt += payMethod.getAmount();
            }
        }

        final double voucherAmt = tempAmt;
        voucher.setVoucherItems(
                retailOrder.getSaleItems().stream().map(item -> {
                    VoucherItem voucherItem = new VoucherItem();
                    ReflectUtil.copy(item, voucherItem, "product", "uom", "supplier", "inventoryBatch");

                    voucherItem.setOwner(item.getOwner());
                    voucherItem.setOriginItemId(item.getId());
                    voucherItem.setSourceItemId(item.getId());

                    voucherItem.setProductQty(item.getProductUomQty());
                    voucherItem.setDiscount(0);

                    Tax tax = taxService.getSaleTax(retailOrder.getCompany(), item.getProduct());
                    voucherItem.setTax(tax);

                    voucherItem.setPriceUnit(voucherAmt);      // 获取收款方式中的金额
                    voucherItem.setPriceTotal(voucherItem.getPriceUnit());

                    // 检查是否为工单的内协的
                    // 找方案上面的价格
                    ServicePlanItem servicePlanItem = SpringManager.getBean(ServicePlanItemRepository.class).findById(item.getOriginnumber()).orElse(null);
                    if (item.getProductRule() == 20) {
                        voucherItem.setSupplier(servicePlanItem.getSupplier());
                        voucherItem.setInventoryBatch(servicePlanItem.getInventoryBatch());
                    }
                    return voucherItem;
                }).collect(Collectors.toSet())
        );

        // 写入凭证之前验证一次（后期可以删除）
        double payAmount = retailOrder.getPaymentMethodSet().stream()
                .filter(retailOrderPayMethod -> !Objects.equals("09", retailOrderPayMethod.getPaymentMethodType().getId()))
                .mapToDouble(RetailOrderPayMethod::getAmount).sum();

        double voucherAmount = voucher.getVoucherItems().stream().mapToDouble(VoucherItem::getPriceTotal).sum();
        if (Math.abs(Arith.round(voucherAmount - payAmount, 2)) > 0.001) {
            throw new RuntimeException("异业合作客户的自费金额与销售凭证金额不相等，请检查！");
        }
        invoke("voucher.create", MapUtil.mapped(voucher));
    }

    private void invoiceCrossIC(RetailOrder retailOrder, List<ServicePlanItem> discountServicePlanItemList) {

        // 一条条的写入挂账逻辑，方便退货反查
        discountServicePlanItemList.forEach(servicePlanItem -> {
            CrossIC crossIC = servicePlanItem.getCrossIC();

            // 检查是否存在 B店 使用 A店 发的异业券( 异业合作券的公司与零售单的公司都不为 1001 )
            if (!Objects.equals(crossIC.getCompany().getId(), retailOrder.getCompany().getId())
                    && !"1001".equals(crossIC.getCompany().getId()) && !"1001".equals(retailOrder.getCompany().getId())) {
                throw new RuntimeException("异业合作券使用有误，请检查！");
            }

            createInvoiceCrossIC(crossIC, retailOrder, servicePlanItem);
        });
    }

    /**
     * 异业挂账执行逻辑
     *
     * @param crossIC         异业信息
     * @param retailOrder     零售单
     * @param servicePlanItem 服务方案明细
     */
    private void createInvoiceCrossIC(CrossIC crossIC, RetailOrder retailOrder, ServicePlanItem servicePlanItem) {
        //  采购凭证
        Voucher voucher = purchaseVoucher(retailOrder, servicePlanItem);

        // 销售凭证
        saleVoucher(voucher, retailOrder, crossIC, servicePlanItem);

        // 跨公司采购
        if (!Objects.equals(crossIC.getCompany().getId(), retailOrder.getCompany().getId())) {
            processCrossICVoucher(crossIC, retailOrder, servicePlanItem);
        }
    }

    private Product getCrossICProduct(ServeType serveType) {
        ServeTypeContrast serveTypeContrast = serveTypeContrastRepository.findByServeTypeIdAndType(serveType.getId(), "crossIC");
        if (Objects.isNull(serveTypeContrast))
            throw new RuntimeException(serveType.getId() + " 服务类型缺少异业写账商品对照表，请联系财务对接人！");
        if (Objects.isNull(serveTypeContrast.getProduct())) throw new RuntimeException("服务类型商品对照表");
        return serveTypeContrast.getProduct();
    }

    private Voucher purchaseVoucher(RetailOrder retailOrder, ServicePlanItem servicePlanItem) {
        Voucher purVoucher = new Voucher();
        purVoucher.setBusinessType(BusinessType.PURCHASE_ORDER);
        ReflectUtil.copy(retailOrder, purVoucher, "dept", "company", "scene", "clerk");

        purVoucher.setPartner(retailOrder.getCompany().getParty().getPatyRoleByType("Supplier"));
        Contract contract = contractService.getContract(purVoucher.getDept(), purVoucher.getPartner(), "distribution", "supplier", "零售异业合作业务");
        purVoucher.setContract(contract);
        purVoucher.setInventoryMode(purVoucher.getContract().getCooperation().getInventoryMode());     //设置库存模式：寄售
        purVoucher.setAccountingMethod(purVoucher.getContract().getCooperation().getAccountingMethod());  // 核算方式：采购价

        purVoucher.setCustomerExpand(retailOrder.getCustomerExpand().getId());

        purVoucher.setOrigin(retailOrder.getId());
        purVoucher.setOriginBusinessType(retailOrder.getInnerBusinessType());
        purVoucher.setSource(retailOrder.getId());
        purVoucher.setSourceBusinessType(retailOrder.getInnerBusinessType());
        purVoucher.setClassification(VoucherType.CROSS_IC);

        // 明细处理
        Set<VoucherItem> voucherItems = new HashSet<>(1);
        VoucherItem voucherItem = new VoucherItem();

        Product product = getCrossICProduct(servicePlanItem.getServeType());
        voucherItem.setOwner(purVoucher.getCompany());
        voucherItem.setProduct(product);
        voucherItem.setUom(product.getUom());
        voucherItem.setProductQty(1d);
        voucherItem.setOriginItemId(servicePlanItem.getId());
        voucherItem.setSourceItemId(retailOrder.getId());
        voucherItem.setSupplier(purVoucher.getPartner());
        voucherItem.setDiscount(0d);
        voucherItem.setPriceUnit(0);
        voucherItems.add(voucherItem);

        Tax tax = taxService.getPurchaseTax(retailOrder.getCompany(), retailOrder.getCompany(), product);   // 0元自采商品
        voucherItem.setTax(tax);

        purVoucher.setVoucherItems(voucherItems);
        purVoucher = invoke("voucher.create", MapUtil.mapped(purVoucher));

        changeFrostQty(purVoucher, "异业合作生成采购凭证");  // 冻结批次

        return purVoucher;
    }

    private Voucher saleVoucher(Voucher purVoucher, RetailOrder retailOrder, CrossIC crossIC, ServicePlanItem servicePlanItem) {
        Voucher voucher = new Voucher();
        voucher.setBusinessType(BusinessType.SALE_ORDER);
        ReflectUtil.copy(purVoucher, voucher, "dept", "company", "scene", "clerk", "origin", "originBusinessType");

        // 来源为采购凭证
        voucher.setSource(purVoucher.getId());
        voucher.setSourceBusinessType(purVoucher.getInnerBusinessType());

        PartyRole partnerCustomer;
        if (Objects.equals(crossIC.getCompany().getId(), retailOrder.getCompany().getId())) {
            partnerCustomer = crossIC.getPartner().getParty().getPatyRoleByType("Customer");   // 取异业合作客户
        } else {
            partnerCustomer = crossIC.getCompany().getParty().getPatyRoleByType("Customer");   // 取对账公司对应的客户
        }
        voucher.setPartner(partnerCustomer);

        Contract contract = contractService.getContract(voucher.getDept(), voucher.getPartner(), "distribution", "customer", "零售异业合作业务");
        voucher.setContract(contract);
        voucher.setInventoryMode(voucher.getContract().getCooperation().getInventoryMode());     //设置库存模式
        voucher.setAccountingMethod(voucher.getContract().getCooperation().getAccountingMethod());  // 核算方式
        voucher.setCustomerExpand(retailOrder.getCustomerExpand().getId());
        voucher.setClassification(VoucherType.CROSS_IC);

        //  明细处理
        Set<VoucherItem> voucherItems = new HashSet<>(1);
        VoucherItem voucherItem = new VoucherItem();

        // 挂账商品
        Product product = getCrossICProduct(servicePlanItem.getServeType());
        voucherItem.setProduct(product);
        voucherItem.setUom(product.getUom());

        voucherItem.setProductQty(1d);
        voucherItem.setOriginItemId(servicePlanItem.getId());
        voucherItem.setSourceItemId(retailOrder.getId());
        voucherItem.setOwner(voucher.getCompany());

        Tax tax = taxService.getSaleTax(retailOrder.getCompany(), product);   // 异业商品销售
        voucherItem.setTax(tax);

        // 对账金额
        if (Objects.equals(crossIC.getCompany().getId(), retailOrder.getCompany().getId())) {
            voucherItem.setPriceUnit(Arith.round(servicePlanItem.getCrossPriceCost() * servicePlanItem.getQtyExchanceCode(), 2));  // 合作成本价
        } else {
            voucherItem.setPriceUnit(Arith.round(servicePlanItem.getCrossAccountPrice() * servicePlanItem.getQtyExchanceCode(), 2));   // 赋能结算价
        }

        // 添加批次
        VoucherItem purVoucherItem = purVoucher.getVoucherItems().iterator().next();    // 由于只有一个商品，这里获取第一个元素
        VoucherInventory voucherInventory = voucherInventoryRepository.findByVoucherItem(purVoucherItem).stream().findAny().orElseThrow(() -> new RuntimeException("找不到批次信息！"));
        voucherItem.setInventoryBatch(voucherInventory.getInventoryBatch());
        voucherItem.setSupplier(purVoucherItem.getSupplier());

        voucherItems.add(voucherItem);
        voucher.setVoucherItems(voucherItems);

        voucher = invoke("voucher.create", MapUtil.mapped(voucher));
        createInvoiceAndFixOriginNumber(retailOrder, voucher);
        return voucher;
    }

    private void processCrossICVoucher(CrossIC crossIC, RetailOrder retailOrder, ServicePlanItem servicePlanItem) {
        // 创建对门店的采购
        Voucher purchaseVoucher = createCrossICPurchaseVoucher(crossIC, retailOrder, servicePlanItem);

        // 创建对异业合作方的销售
        createCrossICSaleVoucher(crossIC, purchaseVoucher, servicePlanItem);
    }

    private Voucher createCrossICPurchaseVoucher(CrossIC crossIC, RetailOrder retailOrder, ServicePlanItem servicePlanItem) {
        Voucher voucher = new Voucher();
        voucher.setBusinessType(BusinessType.PURCHASE_ORDER);

        voucher.setDept(getDept(crossIC.getCompany()));
        voucher.setCompany(crossIC.getCompany());    // 异业对账公司
        voucher.setPartner(retailOrder.getCompany().getParty().getPartyRoleByType("Supplier"));

        Contract contract = contractService.getContract(voucher.getDept(), voucher.getPartner(), "distribution", "supplier", "零售异业合作业务");
        voucher.setContract(contract);
        voucher.setInventoryMode(InventoryMode.IM_OWN);             //设置库存模式：自有
        voucher.setAccountingMethod(AccountingMethod.AM_PURCHASE);  // 核算方式：经销

        voucher.setCustomerExpand(retailOrder.getCustomerExpand().getId());
        voucher.setScene(retailOrder.getScene());
        voucher.setSourceBusinessType(retailOrder.getSourceBusinessType());
        voucher.setSource(retailOrder.getSource());
        voucher.setOriginBusinessType(RetailOrder.class.getSimpleName());
        voucher.setOrigin(retailOrder.getId());
        voucher.setClassification(VoucherType.CROSS_IC);

        //  明细处理
        Set<VoucherItem> voucherItems = new HashSet<>(1);
        VoucherItem voucherItem = new VoucherItem();

        // 挂账商品
        Product product = getCrossICProduct(servicePlanItem.getServeType());
        voucherItem.setProduct(product);
        voucherItem.setUom(product.getUom());

        voucherItem.setProductQty(1d);
        voucherItem.setOriginItemId(servicePlanItem.getId());
        voucherItem.setSourceItemId(retailOrder.getId());
        voucherItem.setOwner(voucher.getCompany());

        Tax tax = taxService.getPurchaseTax(crossIC.getCompany(), retailOrder.getCompany(), product);
        voucherItem.setTax(tax);

        // 对账金额
        voucherItem.setPriceUnit(Arith.round(servicePlanItem.getCrossAccountPrice() * servicePlanItem.getQtyExchanceCode(), 2));   // 赋能结算价
        voucherItems.add(voucherItem);

        voucher.setVoucherItems(voucherItems);
        voucher = invoke("voucher.create", MapUtil.mapped(voucher));

        // 增加账单
        createInvoice(voucher, servicePlanItem.getExchanceCode(), servicePlanItem.getServicePlan().getId());

        changeFrostQty(voucher, "异业合作生成凭证");

        return voucher;
    }

    private void createCrossICSaleVoucher(CrossIC crossIC, Voucher purchaseVoucher, ServicePlanItem servicePlanItem) {
        Voucher voucher = new Voucher();
        voucher.setBusinessType(BusinessType.SALE_ORDER);
        voucher.setCompany(purchaseVoucher.getCompany());
        voucher.setDept(purchaseVoucher.getDept());

        PartyRole partner = crossIC.getPartner().getParty().getPatyRoleByType("Customer");   // 取异业合作客户
        voucher.setPartner(partner);

        Contract contract = contractService.getContract(voucher.getDept(), voucher.getPartner(), "distribution", "supplier", "零售异业合作业务");
        voucher.setContract(contract);
        voucher.setInventoryMode(InventoryMode.IM_OWN);             //设置库存模式：自有
        voucher.setAccountingMethod(AccountingMethod.AM_PURCHASE);  // 核算方式：经销

        voucher.setCustomerExpand(purchaseVoucher.getCustomerExpand());
        voucher.setScene(purchaseVoucher.getScene());
        voucher.setSourceBusinessType(purchaseVoucher.getInnerBusinessType());
        voucher.setSource(purchaseVoucher.getId());
        voucher.setOriginBusinessType(purchaseVoucher.getOriginBusinessType());
        voucher.setOrigin(purchaseVoucher.getOrigin());
        voucher.setClassification(VoucherType.CROSS_IC_CROSS_SALE);

        //  明细处理
        Set<VoucherItem> voucherItems = new HashSet<>(1);
        VoucherItem voucherItem = new VoucherItem();

        // 挂账商品
        Product product = getCrossICProduct(servicePlanItem.getServeType());
        voucherItem.setOwner(purchaseVoucher.getCompany());
        voucherItem.setProduct(product);
        voucherItem.setUom(product.getUom());

        voucherItem.setProductQty(1d);
        voucherItem.setOriginItemId(servicePlanItem.getId());
        voucherItem.setSourceItemId(purchaseVoucher.getId());

        Tax tax = taxService.getSaleTax(purchaseVoucher.getCompany(), product);
        voucherItem.setTax(tax);

        // 对账金额
        voucherItem.setPriceUnit(Arith.round(servicePlanItem.getCrossPriceCost() * servicePlanItem.getQtyExchanceCode(), 2));   // 赋能结算价

        // 添加批次
        VoucherItem purVoucherItem = purchaseVoucher.getVoucherItems().iterator().next();    // 由于只有一个商品，这里获取第一个元素
        VoucherInventory voucherInventory = voucherInventoryRepository.findByVoucherItem(purVoucherItem).stream().findAny().orElseThrow(() -> new RuntimeException("找不到批次信息！"));
        voucherItem.setInventoryBatch(voucherInventory.getInventoryBatch());
        voucherItem.setSupplier(purVoucherItem.getSupplier());

        voucherItems.add(voucherItem);
        voucher.setVoucherItems(voucherItems);

        voucher = invoke("voucher.create", MapUtil.mapped(voucher));

        // 获取异业的票据号码
        createInvoice(voucher, servicePlanItem.getExchanceCode(), servicePlanItem.getServicePlan().getId());
    }

    private void createInvoice(Voucher voucher, String exchangeCode, String ServicePlanId) {
        //  凭证增加 票据号码
        Map m = invoke("voucher.flow.invoice", MapUtil.mapped(voucher));
        JSONObject json = new JSONObject(m);
        json.getJSONArray("invoiceItems").forEach(
                x -> {
                    JSONObject temp = new JSONObject((Map<String, Object>) x);
                    temp.put("name", "异业票据号:" + exchangeCode);
                });

        // 修改来源
        json.put("origin", ServicePlanId);
        json.put("originBusinessType", ServicePlan.class.getSimpleName());
        //增加账单
        invoke("invoice.create", json);
    }
}
